package com.sneakxy.mybatis.commons.repository.query.domain;

import java.util.Iterator;
import java.util.Map;

import org.apache.ibatis.scripting.xmltags.DynamicContext;
import org.apache.ibatis.scripting.xmltags.ExpressionEvaluator;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.session.Configuration;

import com.sneakxy.mybatis.commons.repository.query.parser.MybatisPartTree;

/**
 * @author 潜行的青衣
 */
public class CriteriaSqlNode implements SqlNode {

	public static final String CRITERION_OBJECT_PREFIX = "criterionObject";
	
	private final String parameterName;
	
	private final ExpressionEvaluator evaluator;
	
	private Configuration configuration; 
	
	public CriteriaSqlNode(Configuration configuration, int index) {
		this(new StringBuilder().append(MybatisPartTree.GENERIC_NAME_PREFIX).append(index).toString());
		this.configuration = configuration;
	}
	
	public CriteriaSqlNode(String parameterName) {
		this.parameterName = parameterName;
		this.evaluator = new ExpressionEvaluator();
	}
	
	/* (non-Javadoc)
	 * @see org.apache.ibatis.scripting.xmltags.SqlNode#apply(org.apache.ibatis.scripting.xmltags.DynamicContext)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public boolean apply(DynamicContext context) {
		Map<String, Object> bindings = context.getBindings();
		final Iterable<Condition> iterable = (Iterable<Condition>) this.evaluator.evaluateIterable(parameterName, bindings, false);
		Iterator<Condition> it = iterable.iterator();
		Condition cond = null;
		String name = null;
		int index = 0;
		while(it.hasNext()) {
			cond = it.next();
			name = this.buildItemName(index ++);
			context.bind(name, cond.getCriterion());
			cond.getCriterion().toSql(this.getConfiguration(), cond.getOperator(), new StringBuilder().append(name).append(".value").toString()).apply(context);
		}
		return true;
	}
	
	protected String buildItemName(int index) {
		return new StringBuilder().append(CRITERION_OBJECT_PREFIX).append(index).toString();
	}

	public Configuration getConfiguration() {
		return configuration;
	}

}
